{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "# 4 Function, Module and Package\n",
    "\n",
    "**Functions** facilitate this by providing **decomposition** and **abstraction**.\n",
    "\n",
    "**Decomposition**  creates structure. It allows us to <b>break a problem into modules</b>　that are reasonably self-contained, and that may be reused in different settings.\n",
    "\n",
    "**Abstraction** hides detail. It allows us to use a piece of code as if it were **a black　box**—that is, something whose interior details we cannot see, don’t need to see,and shouldn’t even want to see.\n",
    "\n",
    "\n",
    "### Procedural programming \n",
    "\n",
    "Procedural programming is a programming paradigm that uses a linear or top-down approach. It relies on procedures or subroutines to perform computations.\n",
    "\n",
    "* **Function**\n",
    "\n",
    "### Modular programming\n",
    "\n",
    "Modular programming is the process of subdividing a computer program into separate sub-programs.\n",
    "\n",
    "A module is a separate software component. It can often be used in a variety of applications and functions with other components of the system. \n",
    "\n",
    "Similar functions are grouped in the same unit of programming code and separate functions are developed as separate units of code so that the code can be reused by other applications.\n",
    "\n",
    "Modular programming enables multiple programmers to divide up the work and debug pieces of the program independently.\n",
    "\n",
    "**Modular organization of sources:**  The source codes are split into multiple source files within multiple directories \n",
    "\n",
    "* **Module**\n",
    "\n",
    "* **Package**\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1 Functions \n",
    "\n",
    "\n",
    "### 4.1.1 Function Definitions\n",
    "In Python each function definition is of the form：\n",
    "```python\n",
    "def nameoffunction(list_of_formal_parameters):\n",
    "    body of function \n",
    "```\n",
    "\n",
    "```python\n",
    "def nameoffunction(list_of_formal_parameters):\n",
    "    body of function \n",
    "    return parameters\n",
    "```  \n",
    "\n",
    "* The keyword <b style=\"color:blue\">def</b> introduces a function definition. \n",
    "\n",
    "* It must be followed by the `function name` and the parenthesized <b style=\"color:blue\">()</b> list of `formal parameters`,and by the final colon <b style=\"color:red\">:</b> that ends the line\n",
    "\n",
    "* The statements that form the body of the function start at the next line, and must be `indented`.\n",
    "\n",
    "The function body is any piece of Python code. There is, however, a special statement, <b style=\"color:blue\">return</b>, that can be used only within the body of a function.\n",
    "\n",
    "For example, we could define the function `maxVal` by the code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def maxVal(x, y):    \n",
    "    if x > y:\n",
    "        return x\n",
    "    else:\n",
    "        return y   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The sequence of names (x,y in this example) within the parentheses following the function name are the<b> formal parameters</b>of the function.\n",
    "\n",
    "When the function is used, the formal parameters are bound (as in an assignment statement) to the <b>actual parameters</b> (often referred to as arguments) of the function invocation (also referred to as a function call)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "maxVal(3, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m=maxVal(3, 4)\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### 4.1.2 Positional，Keyword Arguments and Default Values\n",
    "\n",
    "In Python, there are **two ways** that `formal` parameters get bound to `actual parameters`\n",
    "\n",
    "* **1**  <b style=\"color:blue\">Positional</b> \n",
    "\n",
    "  the  `first` formal parameter is bound to the `first` actual parameter,\n",
    "\n",
    "   the `second` formal parameter to the `second` actual, etc.\n",
    "\n",
    "\n",
    "* **2**  <b style=\"color:blue\">Keyword arguments</b>, \n",
    "\n",
    "   in which formals are bound to actuals using the **name** of the formal parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def printName(firstName, lastName, reverse):\n",
    "    if reverse:\n",
    "        print(lastName + ', ' + firstName)\n",
    "    else:\n",
    "        print(firstName, lastName)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    " # all positional argument\n",
    "printName('三', '张', False)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    "#  positional,positional,keyword argument\n",
    "printName('三', '张', reverse = False) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    "# positional,keyword argument,keyword argument\n",
    "printName('三', lastName = '张', reverse = False) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    "# all keyword argument\n",
    "printName(lastName='张', firstName='三', reverse=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "the **keyword arguments** can appear in **any order** in the list of actual parameters, \n",
    "\n",
    "It is<b style=\"color:blue\"> not legal to `follow` a keyword argument with a non-keyword argument</b>.\n",
    "\n",
    "* **Right**:    a `keyword` argument,a `keyword` argument,a `keyword` argument\n",
    "\n",
    "* **Error**:   a keyword argument,`positional` argument"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "positional argument follows keyword argument (<ipython-input-6-f1b9cf1a2313>, line 3)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"<ipython-input-6-f1b9cf1a2313>\"\u001b[1;36m, line \u001b[1;32m3\u001b[0m\n\u001b[1;33m    printName('三', lastName = '张',False)\u001b[0m\n\u001b[1;37m                                      ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m positional argument follows keyword argument\n"
     ]
    }
   ],
   "source": [
    "# a keyword argument  lastName = '张'  \n",
    "# with a non-keyword argument False\n",
    "printName('三', lastName = '张',False) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    "printName('三', lastName = '张',reverse=False) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b>Keyword arguments</b> are commonly used in `conjunction` with `default` parameter values. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# reverse = False: default parameter values\n",
    "def printName(firstName, lastName, reverse = False): \n",
    "    if reverse:\n",
    "        print(lastName + ', ' + firstName)\n",
    "    else:\n",
    "        print(firstName, lastName)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "三 张\n"
     ]
    }
   ],
   "source": [
    "# reverse = False: default parameter values\n",
    "printName('三', '张') \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "张, 三\n"
     ]
    }
   ],
   "source": [
    "# positional\n",
    "printName('三', '张', True) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "张, 三\n"
     ]
    }
   ],
   "source": [
    "# keyword : providing some documentation about True \n",
    "printName('三', '张', reverse = True) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last two invocations of `printName` are semantically equivalent. \n",
    "\n",
    "The last one has **the advantage of providing some `documentation`** for the perhaps mysterious parameter `True`.\n",
    "\n",
    "```python\n",
    " reverse = True\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1.3 Scoping"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Each function` defines **a new name space**, also called **a scope**.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x): # name x used as formal parameter\n",
    "    y = 1   # y local variable。name\n",
    "    \n",
    "    x = x + y  # x local ariable，name \n",
    "    \n",
    "    print('x in local f=', x,'\\n')\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 3\n",
    "y = 2\n",
    "\n",
    "z = f(x) # value of x used as actual parameter\n",
    "\n",
    "print('z =', z)\n",
    "print('x =', x)\n",
    "print('y =', y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1.4 Functions as  arguments\n",
    "\n",
    "In Python, `functions` are **first-class objects**.\n",
    "\n",
    "* That means that they can be treated `like objects of any other type`, e.g., int or list. \n",
    "\n",
    "They have types, e.g.,\n",
    "\n",
    "* `type(abs)` has the value `built-in_function_or_method`\n",
    "\n",
    "* `type(maxVal)` has the value `function`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(abs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(maxVal)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "They can appear in `expressions`, e.g., as \n",
    "\n",
    "* the right-hand side of an assignment statement \n",
    "* `an argument to a function`\n",
    "* elements of sequence,e.g:lists\n",
    "\n",
    "For example,`def bisection`)(**二分法**）\n",
    "\n",
    "The `bisection` method is a root-finding method that\n",
    "\n",
    "* applies to any continuous **functions** for which one knows `two values with opposite signs`.\n",
    "\n",
    "The method consists of repeatedly `bisecting the interval defined by these values` and then selecting the `subinterval` in which the function changes sign, and therefore must contain a root. \n",
    "\n",
    "![](./img/bisection_method.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$x^2-k=0$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def bisection(fun,k,xl,xr,tol,maxiter):\n",
    "    fl = fun(xl,k) # residual for left  bound\n",
    "    fr = fun(xr,k) #resdiual for right bound\n",
    "    numIters=0\n",
    "    for i in range(maxiter):\n",
    "        numIters+=1\n",
    "        # get midpoint\n",
    "        x = 0.5*(xl + xr)\n",
    "        # evaluate resdiual at midpoint\n",
    "        f = fun(x,k)\n",
    "        #  check for convergence\n",
    "        if (abs(f) < tol): \n",
    "            break\n",
    "\n",
    "       # reset the bounds\n",
    "        if (f*fl < 0.0):\n",
    "            # move right bound info to mid\n",
    "            xr = x\n",
    "            fr = f\n",
    "        else:\n",
    "            # move left bound info to mid\n",
    "            xl = x\n",
    "            fl = f\n",
    "    return x,f,numIters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function `bisection` is called **the higher-order function** because it has an `argument` that is itself `a function`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.00030517578125 is close to square root of 25\n",
      "resdiual= 0.0030518509447574615\n",
      "numIters= 14\n"
     ]
    }
   ],
   "source": [
    "def func1(x,k):\n",
    "    return x**2-k\n",
    "\n",
    "k = 25\n",
    "tol = 0.01\n",
    "xl = 0.0\n",
    "xr = 25.0\n",
    "maxiters=100\n",
    "\n",
    "x,f,numIters=bisection(func1,k,xl,xr,tol,maxiters)\n",
    "print(x, 'is close to square root of', k)\n",
    "print('resdiual=', f)\n",
    "print('numIters=', numIters)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1.5 Lambda Expressions\n",
    "\n",
    "* The Python Language Reference ：6.13 `Lambdas` https://docs.python.org/3/reference/expressions.html#lambda\n",
    "\n",
    "Python supports the creation of `anonymous` functions (i.e., functions that are not bound to a name), using the reserved word **lambda**. \n",
    "\n",
    "The general form of a lambda expression is\n",
    "```python\n",
    "lambda <sequence of variable names>: <expression>\n",
    "```\n",
    "Lambda functions can be used wherever function objects are required. \n",
    "\n",
    "* They are syntactically restricted to `a single expression`\n",
    "\n",
    "For example, \n",
    "\n",
    "* the lambda expression `lambda x, y: x*y` returns a function that returns  the product of its two arguments.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "adder = lambda x, y: x+y\n",
    "print(adder(3,6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1.6 The `print()` \n",
    "\n",
    "`print()` built-in function \n",
    "\n",
    "```python\n",
    "print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False)\n",
    "    # Print objects to the text stream file (default standard output sys.stdout),\n",
    "    # *objects denotes variable number of positional arguments packed into a tuple\n",
    "```\n",
    "*  separated by `sep` : the default space `sep=' '`\n",
    "\n",
    "*  followed by `end`: the default newline `end='\\n`\n",
    "\n",
    "    <b style=\"color:blue\"> end=''</b> to suppress the newline.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the default print\n",
      "the default print2\n"
     ]
    }
   ],
   "source": [
    "str1=\"the default print\"\n",
    "str2=\"the default print2\"\n",
    "\n",
    "print(str1)\n",
    "print(str2)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(str1,str2,sep='')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<b style=\"color:blue\"> end=\"\"</b> to suppress the newline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the default print the default print2the default print2"
     ]
    }
   ],
   "source": [
    "print(str1,str2,end=\"\")\n",
    "print(str2,end=\"\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "34\n"
     ]
    }
   ],
   "source": [
    "print(2)\n",
    "print(3,end='')\n",
    "print(4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "<b style=\"color:blue\">print(str.format())</b> \n",
    "\n",
    "https://docs.python.org/3/library/stdtypes.html#str.format\n",
    "\n",
    "Python 3's new style for formatted string via `str` class member function \n",
    "\n",
    "* `str.format()`. \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "str2=\" is:\"\n",
    "int1=11\n",
    "float1=12.6\n",
    "\n",
    "#  the automatic field numbering\n",
    "print('{:>8s} {:^4d} {:>6.2f}'.format(str2,int1,float1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# a keyword argument and a positional argument\n",
    "formatters_str='{ps:<8s} {0:^4d} {1:>6.2f}'\n",
    "print(formatters_str.format(int1,float1,ps=str2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The string on which this method is called can contain `literal text` or `replacement fields`\n",
    "\n",
    "* delimited by braces **`{}`**.\n",
    "\n",
    "Each `replacement field` contains \n",
    "\n",
    "* either the numeric index of a `positional` argument, or the name of a `keyword` argument, \n",
    "\n",
    "* with C-like **format specifiers** beginning with `:` (instead of % in C) such as\n",
    "\n",
    "  * `:4d` for integer,\n",
    "\n",
    "  * `:6.2f` for floating-point number \n",
    "\n",
    "  * `:5s` for string \n",
    "  \n",
    "* align\n",
    "  \n",
    "  * `<`  left\n",
    "  \n",
    "  * `>` right\n",
    "  \n",
    "  * `^` center"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**The `old` style string using `%` operator.**  \n",
    ">\n",
    ">**print('formatting-string' % args)**\n",
    ">\n",
    ">Python 2's `old` style for formatted string using `%` operator. \n",
    ">\n",
    ">The formatting-string could contain C-like format-specifiers, such as \n",
    ">\n",
    ">* `%4d` for integer,\n",
    ">\n",
    ">* `%6.2f` for floating-point number, \n",
    ">\n",
    ">* `%8s` for string. \n",
    ">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "str3=' is '\n",
    "print('The old style %8s,%4d,%6.2f' %(str3,int1,float1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.2 docstring\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2.1 specification\n",
    "\n",
    "**Given a specification of a module**, a programmer can work on implementing that module without worrying unduly about what the otherprogrammers on the team are doing.\n",
    "\n",
    "Moreover, the **other programmers** can use　the specification to start writing code that uses that module without worrying unduly about how that module is to be implemented.\n",
    "\n",
    "<b style=\"color:blue\">specification（规范）</b> of a function defines a <b style=\"color:blue\">contract</b> \n",
    "\n",
    "between \n",
    "\n",
    "* the **implementer** of a function \n",
    "\n",
    "and \n",
    "\n",
    "* those who　(**user－client**)　will be writing programs that use the function.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def bisection(fun, k, xl, xr, tol, maxiter):\n",
    "    \"\"\"\n",
    "      Input:\n",
    "         fun: the function(k)\n",
    "         k : the paraemeter of  fun\n",
    "         xl: lower bound\n",
    "         xr: upper bound\n",
    "         tol: tolerance\n",
    "         maxiter： max iter\n",
    "      return:   \n",
    "           x;  solution \n",
    "           f :final residual\n",
    "           numIters: the count of iters\n",
    "    \"\"\"\n",
    "    fl = fun(xl, k)\n",
    "    fr = fun(xr, k)\n",
    "    numIters = 0\n",
    "    for i in range(maxiter):\n",
    "        numIters += 1\n",
    "        # get midpoint\n",
    "        x = 0.5*(xl + xr)\n",
    "        # evaluate resdiual at midpoint\n",
    "        f = fun(x, k)\n",
    "        #  check for convergence\n",
    "        if (abs(f) < tol):\n",
    "            break\n",
    "\n",
    "       # reset the bounds\n",
    "        if (f*fl < 0.0):\n",
    "            # move right bound info to mid\n",
    "            xr = x\n",
    "            fr = f\n",
    "        else:\n",
    "            # move left bound info to mid\n",
    "            xl = x\n",
    "            fl = f\n",
    "    return x, f, numIters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2.2 docstring \n",
    "\n",
    "The text between the **triple** quotation marks is called a **docstring** in Python.\n",
    "\n",
    "```python\n",
    "\"\"\"\n",
    "quotation marks\n",
    "docstring\n",
    "\"\"\"\n",
    "```\n",
    "or\n",
    "```python\n",
    "\"\"\"  quotation marks     \"\"\"\n",
    "```\n",
    "A string literal which appears as <b  style=\"color:blue\">the first expression</b> in a function,module or class. \n",
    "\n",
    "By convention, Python programmers use **docstrings** to provide **specifications of functions**.\n",
    "\n",
    "These **docstrings** can be **accessed** \n",
    "\n",
    "* 1 using the built-in function **help**\n",
    "\n",
    "\n",
    "* 2 it is recognized by the compiler and put into the \n",
    "\n",
    "```python\n",
    "\n",
    "__doc__  \n",
    "\n",
    "```\n",
    "attribute of the enclosing class, function or module.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(abs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(bisection)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(bisection.__doc__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Furthering Reading 4.2.3  pydoc\n",
    "\n",
    "The `pydoc` module automatically generates documentation from Python modules.\n",
    "\n",
    "The documentation can be presented as pages of `text` on the console, served to a `Web` browser, or saved to `HTML` files.\n",
    "\n",
    "The displayed documentation is derived from the **docstring** (i.e. the `__doc__` attribute) of the object, and recursively of its documentable members. \n",
    "\n",
    " **pydoc to generate its documentation as text on the console / redirect to a text file**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python -m pydoc abs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python -m pydoc abs>>./doc/abs.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load ./doc/abs.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ">**LINE**  magics: `%load`\n",
    ">\n",
    ">   https://ipython.readthedocs.io/en/stable/interactive/magics.html\n",
    ">\n",
    ">Load code into the current frontend.\n",
    ">\n",
    ">Usage:\n",
    ">\n",
    ">```python\n",
    ">%load [options] source\n",
    ">```\n",
    ">where source can be a filename, URL, input history range, macro, or element in the user namespace"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " **start the server and additionally open a web browser to a module index page**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python -m pydoc -b 1234  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Furthering Reading 4.2.4 Documenting Your Python Projects\n",
    "\n",
    "\n",
    ">**code is more often read than written** \n",
    ">               \n",
    ">         --Guido van Rossum\n",
    "\n",
    "The way you `document` your project should suit your specific situation. \n",
    "\n",
    "\n",
    "|Tool|Description|\n",
    "|----|:----------:|\n",
    "|[Sphinx](http://www.sphinx-doc.org/en/stable/)|\tA collection of tools to auto-generate |\n",
    "|[Read The Dcos](https://readthedocs.org/)|Automatic building, versioning, and hosting of your docs for you|\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reference\n",
    "\n",
    "* [Python Toturial : Documentation Strings](https://docs.python.org/3/tutorial/controlflow.html#documentation-strings)s\n",
    "\n",
    "* [PEP0257 - Docstring Convention](https://www.python.org/dev/peps/pep-0257)\n",
    " \n",
    "* [pydoc — Documentation generator and online help system](https://docs.python.org/3/library/pydoc.html)\n",
    "\n",
    "* [Documenting Software](https://github.com/PySEE/home/blob/S2020/guide/doc/DocumentingSoftware)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.3 Modules\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "A **module** is a **.py** file containing Python definitions and statements.\n",
    "\n",
    "Python modules allow us to easily construct \n",
    "\n",
    "* **a program** from code in **multiple files**.\n",
    "\n",
    "\n",
    "\n",
    "For example, a file `circle.py` containing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%file circle.py \n",
    "\n",
    "pi = 3.14159  # executable statements \n",
    "\n",
    "def area(radius):  # function definitions.\n",
    "    return pi*(radius**2)\n",
    "\n",
    "def circumference(radius):\n",
    "    return 2*pi*radius\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A program gets access to a module through an **import** statement\n",
    "\n",
    "```python\n",
    "import ModuleName\n",
    "````"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import circle\n",
    "\n",
    "print(circle.pi)\n",
    "print(circle.area(3))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3.1 Importing Modules\n",
    "\n",
    "**1 a binding for module M**\n",
    "\n",
    "Executing \n",
    "\n",
    "```python\n",
    "import ModuleName \n",
    "```\n",
    "creates <b>a binding for module M</b>,\n",
    "\n",
    "in the importing context,we use **dot** notation to indicate that we are referring to a name defined in the imported module\n",
    "\n",
    "<p>The use of <b>dot notation</b> to fully qualify names avoids the possibility of getting burned by an accidental name clash.\n",
    "\n",
    "```python\n",
    "circle.pi\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import circle\n",
    "print(circle.pi)  # dot notation\n",
    "print(pi)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**2 omit the module name** \n",
    "\n",
    "\n",
    "There is a variant of the `import` statement that allows the importing program to\n",
    "\n",
    "* **omit the module name** \n",
    "\n",
    "when accessing names defined inside the imported module. \n",
    "\n",
    "Executing the statement \n",
    "\n",
    "```python\n",
    "from ModuleName import *\n",
    "```\n",
    "\n",
    "creates <b>bindings</b> in the **current scope**\n",
    "\n",
    "* <b>to all objects </b>defined within M,\n",
    "\n",
    "* but <b>not to M itself</b>. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from circle import *\n",
    "print(pi)   # import *：bindings in the current scope to all objects defined within ModuleName\n",
    "\n",
    "print(area(3))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3.2 The Module Search Path\n",
    "\n",
    "[6.1.2. The Module Search Path](https://docs.python.org/3/tutorial/modules.html#the-module-search-path)\n",
    "\n",
    "When a module named `spam` is imported, the interpreter searches for\n",
    "\n",
    "* a built-in module` \n",
    "\n",
    "* a list of directories given by the variable `sys.path`\n",
    "\n",
    "`first searches` for `a built-in module` with that name. \n",
    "\n",
    "If not found, it then searches for a file named `spam.py` in a list of directories given by the variable `sys.path`. \n",
    "\n",
    "The variable **sys.path** is a list of strings that determines the interpreter’s **search path for modules**.\n",
    "\n",
    "**sys.path** is initialized from these locations:\n",
    "\n",
    "  * The directory containing the input script (or the`current directory` when no file is specified).\n",
    "\n",
    "  * `PYTHONPATH` (a list of directory names, with the same syntax as the shell variable PATH).\n",
    "\n",
    "  * The `installation-dependent` default\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "print(sys.path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Module in the directory of the input script\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%file circle.py \n",
    "\n",
    "pi = 3.14159  # executable statements \n",
    "\n",
    "def area(radius):  # function definitions.\n",
    "    return pi*(radius**2)\n",
    "\n",
    "def circumference(radius):\n",
    "    return 2*pi*radius"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!dir  circle.py "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import circle\n",
    "print(circle.pi)  # dot notation\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Module in the `non-interpreter search path` \n",
    "\n",
    "* Now,we move `circle.py` to the non-interpreter’s search path: `./code/python/`\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!move  circle.py ./code/python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Rfresh Notebook** Click on `Restart & Clear Output` ,you will see\n",
    "\n",
    "```python\n",
    "ModuleNotFoundError \n",
    "\n",
    "ModuleNotFoundError: No module named 'circle'\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import circle\n",
    "print(circle.pi)  # dot notation\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Add to interpreter search path\n",
    "\n",
    "#####  1 sys.path.append\n",
    "You can modify it using standard list operations **add the path of the module** to interpreter’s search path,then call the module"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "sys.path.append('./code/python')\n",
    "#print(sys.path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import circle\n",
    "print(circle.pi)  # dot notation\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "print(sys.path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 2 PYTHONPATH\n",
    "\n",
    "add `PYTHONPATH` to the `System Variable`.set `./code/python` in the value. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.3.3  Execute only if run as a script\n",
    "\n",
    "Add test code in  `circle.py` "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%file ./code/python/circle.py \n",
    "\n",
    "pi = 3.14159  # executable statements \n",
    "\n",
    "def area(radius):  # function definitions.\n",
    "    return pi*(radius**2)\n",
    "\n",
    "def circumference(radius):\n",
    "    return 2*pi*radius\n",
    "\n",
    "# add test code\n",
    "print(area(3.2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "you will see test code is executed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%file ./code/python/demomain.py\n",
    "import sys\n",
    "sys.path.append('./code/python')\n",
    "import circle\n",
    "print(circle.pi) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python ./code/python/demomain.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Add `if __name__ == '__main__':`**\n",
    "\n",
    "```python\n",
    "if __name__ == '__main__':\n",
    "    block\n",
    "```    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%file  ./code/python/circle.py \n",
    "\n",
    "pi = 3.14159  # executable statements \n",
    "\n",
    "def area(radius):  # function definitions.\n",
    "    return pi*(radius**2)\n",
    "\n",
    "def circumference(radius):\n",
    "    return 2*pi*radius\n",
    "\n",
    "if __name__ == '__main__':\n",
    "   # execute only if run as a script\n",
    "   print(area(3.2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!python  ./code/python/demomain.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This **only** runs if run as a script\n",
    "\n",
    "```python\n",
    "if __name__ == '__main__':\n",
    "    block\n",
    "\n",
    "```\n",
    "\n",
    "In short,use this ` if __name__ == '__main__'` block to prevent (certain) code from being run when the module is imported.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**`__name__`**\n",
    "\n",
    "`__name__` is a built-in variable which evaluates to the name of the current module.\n",
    "  \n",
    "* If the source file is `executed as the main program`, the interpreter sets the `__name__` variable to have a value **\\`\\__main\\__\\`**. \n",
    " \n",
    "* If this file is being imported from `another module`, **`__name__`** will be set to the module’s name."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **Further reading**\n",
    ">\n",
    ">`__main__`: https://docs.python.org/3/library/__main__.html\n",
    ">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.4 Packages\n",
    "   \n",
    "https://docs.python.org/3/tutorial/modules.html#packages\n",
    "\n",
    "### 4.4.1 Packages \n",
    "\n",
    "Packages are a way of structuring `Python’s module namespace` by using **“dotted module names”**.\n",
    "   \n",
    "The ` __init__.py  `files are required to make Python treat the **directories** as containing **packages**; \n",
    "   \n",
    "In the simplest case, ` __init__.py ` can just be an **empty** file, but it can also execute initialization code for the package or set the ` __all__ ` variable\n",
    "\n",
    "Suppose you design a collection of modules (a “package”) of numerical computation; \n",
    "\n",
    "```bash   \n",
    "   mymath/                mymath\n",
    "      __init__.py          initialize the  package\n",
    "      circle.py \n",
    "      findroot.py\n",
    "     ...\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./mymath/__init__.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./mymath/__init__.py\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./mymath/circle.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./mymath/circle.py \n",
    "\n",
    "pi = 3.14159  # executable statements \n",
    "\n",
    "def area(radius):  # function definitions.\n",
    "    return pi*(radius**2)\n",
    "\n",
    "def circumference(radius):\n",
    "    return 2*pi*radius\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./mymath/findroot.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./mymath/findroot.py\n",
    "def bisection(fun, k, xl, xr, tol, maxiter):\n",
    "    \"\"\"\n",
    "      Input:\n",
    "         fun: the function(k)\n",
    "         k : the paraemeter of  fun\n",
    "         xl: lower bound\n",
    "         xr: upper bound\n",
    "         tol: tolerance\n",
    "         maxiter： max iter\n",
    "      return:   \n",
    "           x;  solution \n",
    "           f :final residual\n",
    "           numIters: the count of iters\n",
    "    \"\"\"\n",
    "    fl = fun(xl, k)\n",
    "    fr = fun(xr, k)\n",
    "    numIters = 0\n",
    "    for i in range(maxiter):\n",
    "        numIters += 1\n",
    "        # get midpoint\n",
    "        x = 0.5*(xl + xr)\n",
    "        # evaluate resdiual at midpoint\n",
    "        f = fun(x, k)\n",
    "        #  check for convergence\n",
    "        if (abs(f) < tol):\n",
    "            break\n",
    "\n",
    "       # reset the bounds\n",
    "        if (f*fl < 0.0):\n",
    "            # move right bound info to mid\n",
    "            xr = x\n",
    "            fr = f\n",
    "        else:\n",
    "            # move left bound info to mid\n",
    "            xl = x\n",
    "            fl = f\n",
    "    return x, f, numIters\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Users of the package can \n",
    "\n",
    "1. import **individual modules** from the package, \n",
    "\n",
    "```python\n",
    "import packagename.modulename\n",
    "```\n",
    "for example:\n",
    "```python\n",
    "import mymath.findroot\n",
    "import mymath.circle\n",
    "```\n",
    "2 .An alternative way of importing the `submodule` is:\n",
    "```python\n",
    "from packagename import modulename\n",
    "```\n",
    "for example:\n",
    "\n",
    "```python\n",
    "from mymath import findroot\n",
    "from mymath import circle\n",
    "```\n",
    "\n",
    "3. Yet another variation is to import the **desired function or variable directly:**\n",
    "```python\n",
    "from packagename.modulename import function/variable/className\n",
    "```\n",
    "for example:\n",
    "\n",
    "```python\n",
    "from mymath.findroot import bisection\n",
    "from mymath.circle  import area,circumference\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.000305 is close to square root of  25.0\n",
      "\tnumIters = 14\n",
      "\tresdiual = 0.003052\n",
      "radius 3.00\n",
      "\tarea  28.27\n",
      "\tcircumference  18.85\n"
     ]
    }
   ],
   "source": [
    "import mymath.findroot\n",
    "import mymath.circle \n",
    "\n",
    "# from\n",
    "#from mymath import findroot\n",
    "from mymath import circle\n",
    "\n",
    "# function or variable directly\n",
    "# from mymath.findroot import bisection\n",
    "# from mymath.circle  import area,circumference\n",
    "\n",
    "\n",
    "def func1(x,k):\n",
    "    return x**2-k\n",
    "\n",
    "k = 25\n",
    "tol = 0.01\n",
    "xl = 0.0\n",
    "xr =25  \n",
    "maxiters=100\n",
    "\n",
    "x,f,numIters=mymath.findroot.bisection(func1,k,xl,xr,tol,maxiters)\n",
    "#x,f,numIters=findroot.bisection(func1,k,xl,xr,tol,maxiters)\n",
    "#x,f,numIters=bisection(func1,k,xl,xr,tol,maxiters)\n",
    "\n",
    "\n",
    "print(\"{:>8.6f} is close to square root of  {:<4.1f}\".format(x, k))\n",
    "print('\\tnumIters =', numIters)\n",
    "print('\\tresdiual = {:<8.6f}'.format(f))\n",
    "\n",
    "\n",
    "# circle\n",
    "radius=3\n",
    "print(\"radius {:>4.2f}\".format(radius))\n",
    "print(\"\\tarea {:>6.2f}\".format(mymath.circle.area(radius)))\n",
    "print(\"\\tcircumference {:>6.2f}\".format(mymath.circle.circumference(radius)))\n",
    "\n",
    "   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.4.2 import as\n",
    " \n",
    " `import as` is an extension of Python syntax regarding the `import` and `from <module> >import` statements to define aliases(a different name) for imported modules\n",
    "\n",
    "For example, we use `import as` for creating relatively compact or readable code.\n",
    "\n",
    "```python\n",
    "import mymath.findroot\n",
    "\n",
    "x,f,numIters=mymath.findroot.bisection(func1,k,xl,xr,tol,maxiters)\n",
    "```\n",
    "\n",
    "**using `import as`**\n",
    "\n",
    "```python\n",
    "import mymath.findroot as rt\n",
    "\n",
    "x,f,numIters=rt.bisection(func1,k,xl,xr,tol,maxiters)\n",
    "```\n",
    ">**Further reading** [PEP 221 -- Import As](https://www.python.org/dev/peps/pep-0221/)\n",
    ">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Further Reading:\n",
    "\n",
    "* Python Tutorial: Chapter 6 :MODULES https://docs.python.org/3/tutorial/modules.html\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Appendiex : Global Variables\n",
    "\n",
    "Until now, all of the <b>functions</b> we have written <b>communicate</b> with their environment **solely** through \n",
    "\n",
    "**their parameters** and **return values**. \n",
    "\n",
    "```python\n",
    "\n",
    "def yourfunction(their parameters)\n",
    "    code body\n",
    "    \n",
    "    return yourvalues\n",
    "```\n",
    "For the most part, this is exactly as **it should be**.\n",
    "\n",
    "It typically leads to programs that are relatively **easy to read, test, and debug**\n",
    "\n",
    "The **key** to making programs **readable** is **locality**. \n",
    "\n",
    "---\n",
    "Nevertheless, there are times when they are just what is needed.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### A.1 Fibonacci Numbers\n",
    "\n",
    "The **Fibonacci sequence（斐波那契数列）** is the common mathematical function that is usually defined recursively.\n",
    "\n",
    "“They breed like **rabbits**,” -The growth in population is described naturally by the **recurrence:**\n",
    "```bash    \n",
    "females(0) =1\n",
    "\n",
    "females(1) = 1\n",
    "\n",
    "females(n + 2) = females(n+1) + females(n）\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib(n):\n",
    "    \"\"\"Assumes n an int >= 0\n",
    "       Returns Fibonacci of n\"\"\"\n",
    "    if n == 0 or n == 1:\n",
    "        return 1\n",
    "    else:\n",
    "        return fib(n-1) + fib(n-2)\n",
    "\n",
    "def testFib(n):\n",
    "    for i in range(n+1):\n",
    "        print( 'fib of', i, '=', fib(i))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "testFib(12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### A.2 global\n",
    "\n",
    "Suppose we want to know **how many recursive calls** are made? \n",
    "\n",
    "* One way to do that uses **global variables**\n",
    "\n",
    "\n",
    "The functions **fib** and **testFib** both have unfettered access to the object referenced by the variable **numFibCalls**.\n",
    "\n",
    "Global **numFibCalls** occurs in both **fib** and **testFib**. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "numFibCalls=0\n",
    "\n",
    "def fib(x):\n",
    "    \"\"\"Assumes x an int >= 0\n",
    "       Returns Fibonacci of x\"\"\"\n",
    "    \n",
    "    global numFibCalls\n",
    "    \n",
    "    numFibCalls += 1\n",
    "    if x == 0 or x == 1:\n",
    "        return 1\n",
    "    else:\n",
    "        return fib(x-1) + fib(x-2)\n",
    "\n",
    "def testFib(n):\n",
    "    \n",
    "    global numFibCalls\n",
    "    \n",
    "    for i in range(n+1):\n",
    "        numFibCalls = 0\n",
    "        print('fib of', i, '=', fib(i))\n",
    "        print('fib called', numFibCalls, 'times.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "testFib(12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " **remove global numFibCalls**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "numFibCalls=0\n",
    "\n",
    "def fib(x):\n",
    "    \"\"\"Assumes x an int >= 0\n",
    "       Returns Fibonacci of x\"\"\"\n",
    "    #  global numFibCalls\n",
    "    numFibCalls += 1 # local in  fib\n",
    "    if x == 0 or x == 1:\n",
    "        return 1\n",
    "    else:\n",
    "        return fib(x-1) + fib(x-2)\n",
    "\n",
    "def testFib(n):\n",
    "    # global numFibCalls\n",
    "    for i in range(n+1):\n",
    "        numFibCalls = 0 # local in  testfib\n",
    "        print('fib of', i, '=', fib(i))\n",
    "        print('fib called', numFibCalls, 'times.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "testFib(12)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "165px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
